﻿using System;
using System.Collections.ObjectModel;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Bing.Service;
using System.Windows.Media.Imaging;

namespace Microsoft.Bing
{
    /// <summary>
    /// Implements a wrapper class for abstracting a search result
    /// </summary>
    public class SearchResult
    {
        #region Fields
        /// <summary>
        /// The icon URL
        /// </summary>
        private string iconUrl;

        /// <summary>
        /// The Large Icon URL
        /// </summary>
        private string largeIconUrl;
        #endregion

        /// <summary>
        /// Instantiates a <see cref="SearchResult"/> instance.
        /// </summary>
        public SearchResult()
        {
        }

        /// <summary>
        /// Instantiates a <see cref="SearchResult"/> instance.
        /// </summary>
        /// <param name="title">The title of the result</param>
        /// <param name="url">The source Url for the result</param>
        /// <param name="mediaType">The <see cref="MediaTypes">Media Type</see> for the result</param>
        /// <param name="snippet">The snippet, or abstract for the result</param>
        public SearchResult(string title, string url, MediaTypes mediaType, string snippet)
        {
            this.Title = title;
            this.Url = url;
            this.MediaType = mediaType;
            this.Snippet = snippet;
        }

        /// <summary>
        /// Gets/Sets the <see cref="SearchResultKind"/> for the result.
        /// </summary>
        public SearchResultKind Kind { get; set; }

        /// <summary>
        /// Gets/Sets the title for the <see cref="SearchResult"/>.
        /// </summary>
        public string       Title { get; set; }

        /// <summary>
        /// Gets/Sets the Url for the <see cref="SearchResult"/>.
        /// </summary>
        public string       Url { get; set; }

        /// <summary>
        /// Gets/Sets the Display Url for the <see cref="SearchResult"/>.
        /// </summary>
        public string       DisplayUrl { get; set; }

        /// <summary>
        /// Gets or sets the Icon Url for the <see cref="SearchResult"/>. This is the image file for displaying the type iconic for the result.
        /// </summary>
        public string IconUrl
        {
            get
            {
                return this.iconUrl;
            }

            set
            {
                if (this.iconUrl != value)
                {
                    this.iconUrl = value;

                    this.IconImage = CreateImage(this.iconUrl);
                }
            }
        }

        /// <summary>
        /// Gets or sets the Icon Image
        /// </summary>
        /// <remarks>This is directly bindable to an Image.Source</remarks>
        public ImageSource IconImage { get; set; }


        /// <summary>
        /// Gets or sets the Large Icon Url for the <see cref="SearchResult"/>. This is the image file for displaying the large type iconic for the result.
        /// </summary>
        public string LargeIconUrl 
        { 
            get
            {
                return this.largeIconUrl;
            }

            set
            {
                if (this.largeIconUrl != value)
                {
                    this.largeIconUrl = value;

                    this.LargeIconImage = CreateImage(this.largeIconUrl);
                }
            }
        }

        /// <summary>
        /// Gets or sets the large icon image
        /// </summary>
        /// <remarks>This is directly bindable to an Image.Source.</remarks>
        public ImageSource LargeIconImage { get; set; }

        /// <summary>
        /// Gets/Sets the Cached media url for the <see cref="SearchResult"/>.
        /// </summary>
        public string       CacheUrl { get; set; }

        /// <summary>
        /// Gets/Sets the <see cref="MediaTypes">Media Type</see> for the <see cref="SearchResult"/>.
        /// </summary>
        public MediaTypes   MediaType { get; set; }

        /// <summary>
        /// Gets/Sets the snippet, or abstract for the <see cref="SearchResult"/>.
        /// </summary>
        public string       Snippet { get; set; }

        /// <summary>
        /// Gets/Sets the <see cref="System.DateTime"/> for the <see cref="SearchResult"/>.
        /// </summary>
        public DateTime     Date { get; set; }

        /// <summary>
        /// Gets/Sets a <see cref="System.Double">double value</see> which describes the relevancy or weight of the <see cref="SearchResult"/>.
        /// </summary>
        public double       Relevancy { get; set; }

        /// <summary>
        /// Gets/Sets a <see cref="System.UInt32">uint value</see> which describes the width of an image associated with the <see cref="SearchResult"/>.
        /// </summary>
        public uint         ImageWidth { get; set; }

        /// <summary>
        /// Gets/Sets a <see cref="System.UInt32">uint value</see> which describes the height of an image associated with the <see cref="SearchResult"/>.
        /// </summary>
        public uint         ImageHeight { get; set; }

        /// <summary>
        /// Gets/Sets a <see cref="System.UInt32">uint value</see> which describes the file size associated with the <see cref="SearchResult"/>.
        /// </summary>
        public uint         FileSize { get; set; }

        /// <summary>
        /// Gets/Sets a <see cref="Microsoft.Bing.Service.Thumbnail"/> instance for the <see cref="SearchResult"/>.
        /// </summary>
        public Thumbnail    Thumbnail { get; set; }

        /// <summary>
        /// Gets/Sets a <see cref="System.Boolean">boolean value</see> which defines whether a news result is breaking news (i.e. very new)
        /// </summary>
        public bool         IsBreakingNews { get; set; }
        
        //Stock Type Image Url's
        internal const string TYPE_WEB_IMAGE = "TypeHTML48.png";
        internal const string TYPE_GIF_IMAGE = "TypeGIF48.png";
        internal const string TYPE_JPG_IMAGE = "TypeJPG48.png";
        internal const string TYPE_PNG_IMAGE = "TypePNG48.png";
        internal const string TYPE_VIDEO_IMAGE = "TypeVideo48.png";
        internal const string TYPE_NEWS_IMAGE = "TypeNews48.png";
        internal const string TYPE_PHONEBOOK_IMAGE = "TypePhonebook48.png";

        //Stock Type Image Url's (Large)
        internal const string TYPE_WEB_LARGE = "TypeHTML128.png";
        internal const string TYPE_GIF_LARGE = "TypeGIF128.png";
        internal const string TYPE_JPG_LARGE = "TypeJPG128.png";
        internal const string TYPE_PNG_LARGE = "TypePNG128.png";
        internal const string TYPE_VIDEO_LARGE = "TypeVideo128.png";
        internal const string TYPE_NEWS_LARGE = "TypeNews128.png";
        internal const string TYPE_PHONEBOOK_LARGE = "TypePhonebook128.png";

        #region Implementation
        /// <summary>
        /// Creates an image source based on a Uri String
        /// </summary>
        /// <param name="uriString">the Uri to the image</param>
        /// <returns>a BitmapImage or null</returns>
        private static ImageSource CreateImage(string uriString)
        {
            if (string.IsNullOrEmpty(uriString))
            {
                return null;
            }

            Uri uri = null;

            if (Uri.TryCreate(uriString, UriKind.Absolute, out uri))
            {
                return new BitmapImage(uri);
            }

            return null;
        }

        #endregion
    }

    /// <summary>
    /// Implements a collection of <see cref="SearchResult"/> instances.
    /// <remarks>NOTE: This type is observable by <see cref="System.Windows.Controls.ItemsControl"/> instances.</remarks>
    /// </summary>
    public class SearchResults : ObservableCollection<SearchResult>
    {

    }
}
